package com.dykj.fireFighting.common.core.utils;

import org.checkerframework.checker.units.qual.A;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author: zly
 * @Description :
 * @Date: 2022-04-26
 */
public class DateTimeCutUtil {
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private static SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd");
    private static SimpleDateFormat monthType = new SimpleDateFormat("yyyy-MM");

    public static void main(String[] args) throws ParseException {
        Random random = new Random();
        int i = random.nextInt(28) +1;
        System.out.println(i);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date parse = sdf.parse("2021-01-1 00:00:00");
        System.out.println(parse);
     /*  List<String> s = new ArrayList<>();
        String stTime = "2021-08-20";
        String edTime = "2022-11-30";
        //s = TimeCutUtil.cutByType(stTime, edTime, "month");
        //s = TimeCutUtil.cutByType(stTime, edTime, "day");
        s = DateTimeCutUtil.cutByType(stTime, edTime, "quarter");
        //s = TimeCutUtil.cutByType(stTime, edTime, "year");
        System.out.println(s);*/
    /*   List<String> list1 = new ArrayList<>();
       list1.add("1");
        list1.add("2");
        list1.add("3");
        List<String> list2 = new ArrayList<>();
        list2.add("1");
        list2.add("2");
        List<String> strings = subList2(list1, list2);
        System.out.println(strings);*/
    }



    /**
     * 差集(基于java8新特性)优化解法2 适用于大数据量
     *  求List1中有的但是List2中没有的元素
     * @param list1
     * @param list2
     * @return
     */
    public static List<String> subList2(List<String> list1, List<String> list2) {
        Map<String, String> tempMap = list2.parallelStream().collect(Collectors.toMap(Function.identity(), Function.identity(), (oldData, newData) -> newData));
        return list1.parallelStream().filter(str->{
            return !tempMap.containsKey(str);
        }).collect(Collectors.toList());
    }


    /**
     *
     * @param startDate
     * @param endDate
     * @param type  year 年 month 月  day 天（日） quarter 季
     * @return
     */
    public static List<String> cutByType(String startDate,String endDate,String type) throws ParseException {
        List<String> result = new ArrayList<>();

        String stTime = startDate + " 00:00:00";
        String edTime = endDate+" 23:59:59";
        Long startTime = dateToStamp(stTime);
        Long endTime = dateToStamp(edTime);

        List<Long> beginDateList = new ArrayList<Long>();
        List<Long> endDateList = new ArrayList<Long>();


        if("year".equals(type)){
            result = getYearList(startDate, endDate);
        } else if("quarter".equals(type)){
            result=getSeasonList(startDate,endDate);
        } else if("month".equals(type)){
            getIntervalTimeByMonth(startTime, endTime, beginDateList, endDateList);
            for (int i = 0; i < beginDateList.size(); i++) {
                Long beginStr = beginDateList.get(i);
                String begin1 = monthType.format(new Date(beginStr));
                result.add(begin1);
            }
        } else if("day".equals(type)){
            getIntervalTimeByDay(startTime, endTime, beginDateList, endDateList);
            for (int i = 0; i < beginDateList.size(); i++) {
                Long beginStr = beginDateList.get(i);
                String begin1 = sdf2.format(new Date(beginStr));
                result.add(begin1);
            }
        }
        return result;
    }

    /**
     * 获取时间段内所有年份
     * @param startDate
     * @param endDate
     * @return
     * @throws ParseException
     */
    private static List<String> getYearList(String startDate, String endDate) throws ParseException {
        int s = Integer.parseInt(startDate.substring(0,4));
        int e = Integer.parseInt(endDate.substring(0,4));
        List<String> years = new ArrayList<>();
        while (s <= e) {
            years.add(Integer.toString(s));
            s+=1;

        }
        return years;
    }

    /**
     * 获取时间段内所有季度
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     */
    private static List<String> getSeasonList(String startDate, String endDate) {
        LocalDate startTime =
                LocalDate.parse(startDate, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        LocalDate endTime =
                LocalDate.parse(endDate, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        // 取当月第一天, 避免startTime的日期大于endTime计算不出来的情况
        startTime = LocalDate.of(startTime.getYear(), startTime.getMonthValue(), 1);
        endTime = LocalDate.of(endTime.getYear(), endTime.getMonthValue(), 1);
        Set<String> set = new HashSet<>();
        LocalDate mark = startTime;
        while (true) {
            if (mark.isBefore(endTime) || mark.isEqual(endTime)) {
                String season = String.valueOf(mark.getYear()) +"-"+ String.valueOf((mark.getMonthValue() + 2) / 3);
                set.add(season);
                // 加一个月
                mark = mark.plusMonths(1);
            } else {
                break;
            }
        }

        //
        return set.stream().sorted().collect(Collectors.toList());
    }


    /*
     * 将时间转换为时间戳
     */
    private static Long dateToStamp(String s) {
        try {
            Date date = sdf.parse(s);
            long ts = date.getTime();
            return ts;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }



    /**
     * 以季度分割时间段
     * 此处季度是以 1-3月   4-6月   7-9月  10-12月 划分
     * @param startTime     开始时间戳(毫秒)
     * @param endTime       结束时间戳(毫秒)
     * @param beginDateList 开始段时间戳 和 结束段时间戳 一一对应
     * @param endDateList   结束段时间戳 和 开始段时间戳 一一对应
     */
    private static void getIntervalTimeByQuarter(Long startTime, Long endTime, List<Long> beginDateList, List<Long> endDateList) {
        Date startDate = new Date(startTime);
        Date endDate = new Date(endTime);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startDate);
        int month = calendar.get(Calendar.MONTH) + 1;
        switch (month) {
            case 12:
            case 3:
            case 6:
            case 9:
                addTime(beginDateList, endDateList, startDate, endDate, calendar, 1);
                break;
            case 1:
            case 4:
            case 7:
            case 10:
                addTime(beginDateList, endDateList, startDate, endDate, calendar, 3);
                break;
            case 2:
            case 5:
            case 8:
            case 11:
                addTime(beginDateList, endDateList, startDate, endDate, calendar, 2);
                break;
        }
    }

    private static void addTime(List<Long> beginDateList, List<Long> endDateList, Date startDate, Date endDate, Calendar calendar, int i) {
        beginDateList.add(startDate.getTime());
        calendar.add(Calendar.MONTH, i);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.add(Calendar.DATE, -1);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        if (calendar.getTimeInMillis() > endDate.getTime()) {
            endDateList.add(endDate.getTime());
        } else {
            endDateList.add(calendar.getTimeInMillis());
            while (calendar.getTimeInMillis() < endDate.getTime()) {
                calendar.add(Calendar.DATE, 1);
                calendar.set(Calendar.HOUR_OF_DAY, 0);
                calendar.set(Calendar.MINUTE, 0);
                calendar.set(Calendar.SECOND, 0);
                beginDateList.add(calendar.getTimeInMillis());
                calendar.add(Calendar.MONTH, 3);
                calendar.set(Calendar.DAY_OF_MONTH, 1);
                calendar.add(Calendar.DATE, -1);
                calendar.set(Calendar.HOUR_OF_DAY, 23);
                calendar.set(Calendar.MINUTE, 59);
                calendar.set(Calendar.SECOND, 59);
                if (calendar.getTimeInMillis() < endDate.getTime()) {
                    endDateList.add(calendar.getTimeInMillis());
                } else {
                    endDateList.add(endDate.getTime());
                }
            }
        }
    }

    /**
     * 以周分割时间段
     *
     * @param startTime     开始时间戳(毫秒)
     * @param endTime       结束时间戳(毫秒)
     * @param beginDateList 开始段时间戳 和 结束段时间戳 一一对应
     * @param endDateList   结束段时间戳 和 开始段时间戳 一一对应
     */
    private static void getIntervalTimeByWeek(Long startTime, Long endTime, List<Long> beginDateList, List<Long> endDateList) {
        try {
            Date startDate = new Date(startTime);
            Calendar calendar  = Calendar.getInstance();
            calendar.setFirstDayOfWeek(Calendar.MONDAY);
            calendar.setTime(startDate);
            boolean bool = true;
            while (calendar.getTimeInMillis() <= endTime) {
                int week1 = calendar.get(Calendar.DAY_OF_WEEK) - 1;// 周几
                if (bool || week1 == 0 || week1 == 1) {
                    if (week1 == 0) {// 周日
                        calendar.set(Calendar.HOUR_OF_DAY, 23);
                        calendar.set(Calendar.MINUTE, 59);
                        calendar.set(Calendar.SECOND, 59);
                        endDateList.add(calendar.getTimeInMillis());
                    } else {
                        calendar.set(Calendar.HOUR_OF_DAY, 0);
                        calendar.set(Calendar.MINUTE, 0);
                        calendar.set(Calendar.SECOND, 0);
                        beginDateList.add(calendar.getTimeInMillis());
                    }
                    bool = false;
                }
                calendar.add(Calendar.DAY_OF_MONTH, 1);// 加一天
            }
            endDateList.add(endTime);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 按照月份分割一段时间
     *
     * @param startTime     开始时间戳(毫秒)
     * @param endTime       结束时间戳(毫秒)
     * @param beginDateList 开始段时间戳 和 结束段时间戳 一一对应
     * @param endDateList   结束段时间戳 和 开始段时间戳 一一对应
     */
    private static void getIntervalTimeByMonth(Long startTime, Long endTime, List<Long> beginDateList, List<Long> endDateList) {
        Date startDate = new Date(startTime);
        Date endDate = new Date(endTime);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startDate);
        beginDateList.add(calendar.getTimeInMillis());
        while (calendar.getTimeInMillis() < endDate.getTime()) {
            calendar.add(Calendar.MONTH, 1);
            calendar.set(Calendar.DAY_OF_MONTH, 1);
            calendar.add(Calendar.DATE, -1);
            calendar.set(Calendar.HOUR_OF_DAY, 23);
            calendar.set(Calendar.MINUTE, 59);
            calendar.set(Calendar.SECOND, 59);
            if(calendar.getTimeInMillis() < endDate.getTime()){
                endDateList.add(calendar.getTimeInMillis());
            } else {
                endDateList.add(endDate.getTime());
                break;
            }
            calendar.add(Calendar.DATE, 1);
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            beginDateList.add(calendar.getTimeInMillis());
        }
    }

    /**
     * 按照天分割一段时间
     *
     * @param startTime     开始时间戳(毫秒)
     * @param endTime       结束时间戳(毫秒)
     * @param beginDateList 开始段时间戳 和 结束段时间戳 一一对应
     * @param endDateList   结束段时间戳 和 开始段时间戳 一一对应
     */
    private static void getIntervalTimeByDay(Long startTime, Long endTime, List<Long> beginDateList, List<Long> endDateList) {
        Date startDate = new Date(startTime);
        Date endDate = new Date(endTime);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startDate);
        beginDateList.add(calendar.getTimeInMillis());
        while (calendar.getTimeInMillis() < endDate.getTime()) {
            calendar.set(Calendar.HOUR_OF_DAY, 23);
            calendar.set(Calendar.MINUTE, 59);
            calendar.set(Calendar.SECOND, 59);
            if(calendar.getTimeInMillis() < endDate.getTime()){
                endDateList.add(calendar.getTimeInMillis());
            } else {
                endDateList.add(endDate.getTime());
                break;
            }
            calendar.add(Calendar.DATE, 1);
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            beginDateList.add(calendar.getTimeInMillis());
        }
    }

    /**
     * 按照天分割一段时间
     *
     * @param startTime     开始时间戳(毫秒)
     * @param endTime       结束时间戳(毫秒)
     * @param beginDateList 开始段时间戳 和 结束段时间戳 一一对应
     * @param endDateList   结束段时间戳 和 开始段时间戳 一一对应
     */
    private static void getIntervalTimeByDay2(Long startTime, Long endTime, List<Long> beginDateList, List<Long> endDateList, int stHour, int edHour) {
        Date startDate = new Date(startTime);
        Date endDate = new Date(endTime);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startDate);
        beginDateList.add(calendar.getTimeInMillis());
        int i = 0;
        while (calendar.getTimeInMillis() < endDate.getTime()) {
            if(i != 0 && stHour != 0) {
                calendar.add(Calendar.DATE, 1);
            }
            calendar.set(Calendar.HOUR_OF_DAY, edHour);
            calendar.set(Calendar.MINUTE, 59);
            calendar.set(Calendar.SECOND, 59);
            if(calendar.getTimeInMillis() < endDate.getTime()){
                endDateList.add(calendar.getTimeInMillis());
            } else {
                endDateList.add(endDate.getTime());
                break;
            }
            calendar.set(Calendar.HOUR_OF_DAY, stHour);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            beginDateList.add(calendar.getTimeInMillis());
            i++;
        }
    }

    /**
     * 获取指定年月的第一天
     * @param date
     * @return
     */
    private static String getFirstDayOfMonth(String date) {
        String[] split = date.split("-");
        Calendar cal = Calendar.getInstance();
        //设置年份
        cal.set(Calendar.YEAR, Integer.valueOf(split[0]));
        //设置月份
        cal.set(Calendar.MONTH, Integer.valueOf(split[1]) - 1);
        //获取某月最小天数
        int firstDay = cal.getMinimum(Calendar.DATE);
        //设置日历中月份的最小天数
        cal.set(Calendar.DAY_OF_MONTH,firstDay);

        return sdf2.format(cal.getTime());
    }

    /**
     * 获取指定年月的最后一天
     * @param date
     * @return
     */
    private static String getLastDayOfMonth(String date) {
        String[] split = date.split("-");
        Calendar cal = Calendar.getInstance();
        //设置年份
        cal.set(Calendar.YEAR, Integer.valueOf(split[0]));
        //设置月份
        cal.set(Calendar.MONTH, Integer.valueOf(split[1]) - 1);
        //获取某月最大天数
        int lastDay = cal.getActualMaximum(Calendar.DATE);
        //设置日历中月份的最大天数
        cal.set(Calendar.DAY_OF_MONTH, lastDay);

        return sdf2.format(cal.getTime());
    }

}
